#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::analyse() {
    programme();
    cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::programme() {
    // <programme> ::= debut <seqInst> fin FIN_FICHIER

    sauterSymCour("debut");
    seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }

    do {
        inst();
        sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "si" || ls.getSymCour() == "tantque" || ls.getSymCour() == "repeter");
    // tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::inst() {
    // <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>
    if (ls.getSymCour() == "si") {
        instSi();
    } else if (ls.getSymCour() == "tantque") {
        instTq();
    } else if (ls.getSymCour() == "repeter") {
        instRepeter();
    } else if (ls.getSymCour() == "lire") {
        instLire();
    } else if (ls.getSymCour() == "ecrire") {
        instEcrire();
    } else if (ls.getSymCour() == "<VARIABLE>") {
        affectation();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::affectation() {
    // <affectation> ::= <variable> = <expression>

    sauterSymCour("<VARIABLE>");
    sauterSymCour("=");
    expBool();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expression() {
    // <expression> ::= <terme> { <opAdd> <terme> } | <CHAINE> { + <CHAINE> }

    if (ls.getSymCour() == "<CHAINE>") {
        sauterSymCour("<CHAINE>");
        while (ls.getSymCour() == "+") {
            sauterSymCour("+");
            sauterSymCour("<CHAINE>");
        }
    } else {
        terme();
        while (ls.getSymCour() == "+" || ls.getSymCour() == "-") {
            opAdd();
            terme();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::terme() {
    // <terme> ::= <facteur> { <opMult> <facteur> }

    facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
        opMult();
        facteur();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::facteur() {
    // <facteur> ::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> )

    if (ls.getSymCour() == "<VARIABLE>")
        sauterSymCour("<VARIABLE>");
    else if (ls.getSymCour() == "<ENTIER>")
        sauterSymCour("<ENTIER>");
    else if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
        opUnaire();
        expBool();
    } else if (ls.getSymCour() == "(") {
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
    } else
        erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opAdd()
// <opAdd>  ::= + | -
{
    if (ls.getSymCour() == "+") {
        sauterSymCour("+");
    } else if (ls.getSymCour() == "-") {
        sauterSymCour("-");
    } else
        erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opMult()
// <opAdd>  ::= + | -
{
    if (ls.getSymCour() == "*") {
        sauterSymCour("*");
    } else if (ls.getSymCour() == "/") {
        sauterSymCour("/");
    } else
        erreur("<opMult>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::expBool()
// <expBool> ::= <termeBool> { ou <termeBool> }
{
    termeBool();
    while (ls.getSymCour() == "ou") {
        sauterSymCour("ou");
        termeBool();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::termeBool()
// <termeBool> ::= <relation> { et <relation> }
{
    relation();
    while (ls.getSymCour() == "et") {
        sauterSymCour("et");
        relation();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::relation()
//  <relation> ::= <expression> { <opRel> <expression> }
{
    expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" || ls.getSymCour() == ">" || ls.getSymCour() == "<=" || ls.getSymCour() == ">=") {
        opRel();
        expression();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opRel()
//  <opRel> ::= == | != | < | <= | > | >=
{
    if (ls.getSymCour() == "==") {
        sauterSymCour("==");
    } else if (ls.getSymCour() == "!=") {
        sauterSymCour("!=");
    } else if (ls.getSymCour() == "<") {
        sauterSymCour("<");
    } else if (ls.getSymCour() == ">") {
        sauterSymCour(">");
    } else if (ls.getSymCour() == "<=") {
        sauterSymCour("<=");
    } else if (ls.getSymCour() == ">=") {
        sauterSymCour(">=");
    } else
        erreur("<opRel>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::opUnaire()
//  <opUnaire> ::= - | non
{
    if (ls.getSymCour() == "-") {
        sauterSymCour("-");
    } else if (ls.getSymCour() == "non")
        sauterSymCour("non");
    else
        erreur("<opUnaire>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instSi()
//  <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
{
    sauterSymCour("si");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();
    while (ls.getSymCour() == "sinonsi") {
        sauterSymCour("sinonsi");
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
    }
    if (ls.getSymCour() == "sinon") {
        sauterSymCour("sinon");
        seqInst();
    }
    sauterSymCour("finsi");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instTq()
//  <instTq> ::= tantque ( <expBool> ) <seqInst> fintq
{
    sauterSymCour("tantque");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("fintq");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instRepeter()
//  <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
{
    sauterSymCour("repeter");
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instPour()
//  <instPour> ::= pour ( <affectation> ; <expBool> ; <affectation> ) <seqInst> finpour
{
    sauterSymCour("pour");
    sauterSymCour("(");
    affectation();
    sauterSymCour(";");
    expBool();
    sauterSymCour(";");
    affectation();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("finpour");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instLire()
//  <instLire> ::= lire ( <variable> )
{
    sauterSymCour("lire");
    sauterSymCour("(");
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instEcrire()
//  <instEcrire> ::= ecrire ( <expression> | <chaine> )
{
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour() == "<CHAINE>") {
        sauterSymCour("<CHAINE>");
    } else {
        expression();
    }
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
        exit(0); // plus tard, on levera une exception
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::sauterSymCour(string ch) {
    testerSymCour(ch);
    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<CHAINE>" || ls.getSymCour() == "<ENTIER>") {
        ts.chercheAjoute(ls.getSymCour());
    }
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
            << ls.getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
